package com.atguigu.gmall.wms.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.wms.vo.StockLockedVo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.gmall.common.bean.PageResultVo;
import com.atguigu.gmall.common.bean.PageParamVo;

import com.atguigu.gmall.wms.mapper.WareSkuMapper;
import com.atguigu.gmall.wms.entity.WareSkuEntity;
import com.atguigu.gmall.wms.service.WareSkuService;
import org.springframework.util.CollectionUtils;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuMapper, WareSkuEntity> implements WareSkuService {
    @Autowired
    StringRedisTemplate redisTemplate;
    @Override
    public PageResultVo queryPage(PageParamVo paramVo) {
        IPage<WareSkuEntity> page = this.page(
                paramVo.getPage(),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageResultVo(page);
    }

    @Override
    public List<StockLockedVo> checkAndLock(List<StockLockedVo> stockLockedVos) {
        if(CollectionUtils.isEmpty(stockLockedVos)){
            return null;//锁定失败
        }
        //1、验库存+锁定库存
        stockLockedVos.forEach(stockLockedVo -> {
            //遍历一个锁一个:如果库存足够直接锁库存 需要加锁
            checkLock(stockLockedVo);//遍历过程中 锁库存成功设置给stockLockedVo的属性值成功，stockLockedVos中的对象属性值也改变了
        });
        //2、判断所有的sku库存是否锁定成功
        //遍历stockLockedVos 如果有锁定失败的，再挑出锁定成功的释放库存
        List<StockLockedVo> lockedVos = stockLockedVos.stream().filter(stockLockedVo ->
                stockLockedVo.getStocked()).collect(Collectors.toList());
        List<StockLockedVo> unlockedVos = stockLockedVos.stream().filter(stockLockedVo ->
                !stockLockedVo.getStocked()).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(unlockedVos)){//有锁定失败的库存
            //释放锁定成功的库存
            if(!CollectionUtils.isEmpty(lockedVos)){
                lockedVos.forEach(lockVo->{
                    baseMapper.unlockStock(lockVo.getWareSkuId() , lockVo.getCount());
                });
            }
            return null;
        }
        //库存锁定成功：用户提交订单时 锁定的库存，但是用户不一定支付订单，订单也不一定能够创建成功
        //以后也可能释放库存,需要将当前订单的锁定库存信息存到redis中缓存
        redisTemplate.opsForValue().set("lock:stock:"+lockedVos.get(0).getOrderToken(),
                // 以后值还要还原为lockVo对象的集合  使用json
                JSON.toJSONString(lockedVos));
        return lockedVos;
    }
    @Autowired
    RedissonClient redissonClient; //还需要配置创建对象注入到容器中
    //检查锁定库存
    private void checkLock(StockLockedVo stockLockedVo) {
        //1、加锁
        String skuId = stockLockedVo.getSkuId();
        RLock fairLock = redissonClient.getFairLock("lock:stock:" + skuId);
        fairLock.lock();
        try {
            //2、验库存
            List<WareSkuEntity> wareSkuEntities = baseMapper.queryWareSkuEntities(skuId, stockLockedVo.getCount());
            if(CollectionUtils.isEmpty(wareSkuEntities)){
                return ;//stockLockedVo的锁定状态默认为false
            }
            //有库存: 从库存足够的集合中挑选 和当前用户收货地址 最近的仓库 锁库存
            WareSkuEntity wareSkuEntity = wareSkuEntities.get(0);
            //3、锁库存
            Boolean stock = baseMapper.lockStock(wareSkuEntity.getId().toString(), stockLockedVo.getCount());
            if(!stock){
                return ;//锁定库存失败
            }
            //库存锁定成功
            stockLockedVo.setWareSkuId(wareSkuEntity.getId().toString());
            stockLockedVo.setStocked(true);
        } finally {
            //4、释放锁
            fairLock.unlock();
        }
    }

}